/**
  ******************************************************************************
  * @file    bsp_usart.c
  * @author  Iron
  * @date    2018-08-03
  * @version v1.0
  * @brief   bsp usart c file
  */

/** @addtogroup GROUP_BSP
  * @{
  */

/* includes ------------------------------------------------------------------*/
#include "FreeRTOS.h"
#include "stm32f4xx_hal.h"
#include "bsp_usart.h"

/* BEBUG LOG */
#include "debug_log.h"
#define LOG_LOCAL_LEVEL DBG_LOG_DEBUG
DBG_LOG_TAG("BSP_USART");

/* rtos enter isr ----------------------------------------------------------*/
/* RTOS ISR */
#define BSP_USART_ENTER_ISR() \
    UBaseType_t uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR()

#define BSP_USART_EXIT_ISR() \
    portCLEAR_INTERRUPT_MASK_FROM_ISR(uxSavedInterruptStatus)

#define BSP_USART_IRQ_PRE_PRI  10       /* 5 < PRI < 15*/
#define BSP_USART_IRQ_SUB_PRI  0

/* private macro -------------------------------------------------------------*/
#define USRAT1_ENABLE
#define USRAT2_ENABLE
#define USRAT3_ENABLE
#define URAT4_ENABLE
#define URAT5_ENABLE
#define USRAT6_ENABLE

// USART DMA CONFIG
//#define DRV_USART1_USE_DMA_RX  // not implement
#define DRV_USART1_USE_DMA_TX

//#define DRV_USART2_USE_DMA_RX  // not implement
#define DRV_USART2_USE_DMA_TX

//#define DRV_USART3_USE_DMA_RX  // not implement
#define DRV_USART3_USE_DMA_TX

//#define DRV_UART4_USE_DMA_RX  // not implement
#define DRV_UART4_USE_DMA_TX

//#define DRV_UART5_USE_DMA_RX  // not implement
#define DRV_UART5_USE_DMA_TX

//#define DRV_USART6_USE_DMA_RX  // not implement
#define DRV_USART6_USE_DMA_TX

/* private typedef -----------------------------------------------------------*/
#define USART_RX_FULL                   1
#define USART_RX_FIFO_SIZE              128

struct usart_rx_fifo
{
    uint16_t in;
    uint16_t out;
    uint16_t size;
    uint8_t is_full;
    uint8_t buffer[USART_RX_FIFO_SIZE];
};

typedef struct bsp_usart
{
    UART_HandleTypeDef *UartHandle;
    uint8_t ref;
    struct usart_rx_fifo rx;
    usart_isr_rx_indicate_t rx_indicate;
    usart_isr_tx_complete_t tx_complete;
    void *handle;
} bsp_usart_t;

// bsp usrat handler
static bsp_usart_t usart_handler[BSP_USART_MAX];

/* private variables ---------------------------------------------------------*/
#ifdef USRAT1_ENABLE
    UART_HandleTypeDef huart1;
    #ifdef DRV_USART1_USE_DMA_TX
        DMA_HandleTypeDef hdma_usart1_tx;
    #endif
    #ifdef DRV_USART1_USE_DMA_RX
        DMA_HandleTypeDef hdma_usart1_rx;
    #endif
#endif

#ifdef USRAT2_ENABLE
    UART_HandleTypeDef huart2;
    #ifdef DRV_USART2_USE_DMA_TX
        DMA_HandleTypeDef hdma_usart2_tx;
    #endif
    #ifdef DRV_USART2_USE_DMA_RX
        DMA_HandleTypeDef hdma_usart2_rx;
    #endif
#endif

#ifdef USRAT3_ENABLE
    UART_HandleTypeDef huart3;
    #ifdef DRV_USART3_USE_DMA_TX
        DMA_HandleTypeDef hdma_usart3_tx;
    #endif
    #ifdef DRV_USART3_USE_DMA_RX
        DMA_HandleTypeDef hdma_usart3_rx;
    #endif
#endif

#ifdef URAT4_ENABLE
    UART_HandleTypeDef huart4;
    #ifdef DRV_UART4_USE_DMA_TX
        DMA_HandleTypeDef hdma_uart4_tx;
    #endif
    #ifdef DRV_UART4_USE_DMA_RX
        DMA_HandleTypeDef hdma_uart4_rx;
    #endif
#endif

#ifdef URAT5_ENABLE
    UART_HandleTypeDef huart5;
    #ifdef DRV_UART5_USE_DMA_TX
        DMA_HandleTypeDef hdma_uart5_tx;
    #endif
    #ifdef DRV_UART5_USE_DMA_RX
        DMA_HandleTypeDef hdma_uart5_rx;
    #endif

#endif
#ifdef USRAT6_ENABLE
    UART_HandleTypeDef huart6;
    #ifdef DRV_USART6_USE_DMA_TX
        DMA_HandleTypeDef hdma_usart6_tx;
    #endif
    #ifdef DRV_USART6_USE_DMA_RX
        DMA_HandleTypeDef hdma_usart6_rx;
    #endif
#endif

/* private function prototypes -----------------------------------------------*/
/* private functions ---------------------------------------------------------*/
static void bsp_usart_tx_complete_cb(uint32_t uart);
static void bsp_usart_irq(uint32_t uart);
static void bsp_usart_dma_irq(DMA_HandleTypeDef *hdma);

/* extern functions ----------------------------------------------------------*/
void _Error_Handler(char *file, int line);

/**
* @brief MX USART UART Init
*/
#ifdef USRAT1_ENABLE
/* USART1 init function */
static void MX_USART1_UART_Init(bsp_usart_t *usart, uint32_t BaudRate)
{
    if (usart == NULL)
    {
        _Error_Handler(__FILE__, __LINE__);
    }

    huart1.Instance = USART1;
    huart1.Init.BaudRate = BaudRate;
    huart1.Init.WordLength = UART_WORDLENGTH_8B;
    huart1.Init.StopBits = UART_STOPBITS_1;
    huart1.Init.Parity = UART_PARITY_NONE;
    huart1.Init.Mode = UART_MODE_TX_RX;
    huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
    huart1.Init.OverSampling = UART_OVERSAMPLING_16;
    if (HAL_UART_Init(&huart1) != HAL_OK)
    {
        _Error_Handler(__FILE__, __LINE__);
    }
    usart->UartHandle = &huart1;
    /* enable rx irq */
    HAL_NVIC_SetPriority(USART1_IRQn, BSP_USART_IRQ_PRE_PRI, BSP_USART_IRQ_SUB_PRI);
    HAL_NVIC_EnableIRQ(USART1_IRQn);
    /* enable interrupt */
    __HAL_UART_ENABLE_IT(usart->UartHandle, UART_IT_RXNE);
}
#endif
#ifdef USRAT2_ENABLE
/* USART2 init function */
static void MX_USART2_UART_Init(bsp_usart_t *usart, uint32_t BaudRate)
{
    if (usart == NULL)
    {
        _Error_Handler(__FILE__, __LINE__);
    }

    huart2.Instance = USART2;
    huart2.Init.BaudRate = BaudRate;
    huart2.Init.WordLength = UART_WORDLENGTH_8B;
    huart2.Init.StopBits = UART_STOPBITS_1;
    huart2.Init.Parity = UART_PARITY_NONE;
    huart2.Init.Mode = UART_MODE_TX_RX;
    huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
    huart2.Init.OverSampling = UART_OVERSAMPLING_16;
    if (HAL_UART_Init(&huart2) != HAL_OK)
    {
        _Error_Handler(__FILE__, __LINE__);
    }
    usart->UartHandle = &huart2;
    /* enable rx irq */
    HAL_NVIC_SetPriority(USART2_IRQn, BSP_USART_IRQ_PRE_PRI, BSP_USART_IRQ_SUB_PRI);
    HAL_NVIC_EnableIRQ(USART2_IRQn);
    /* enable interrupt */
    __HAL_UART_ENABLE_IT(usart->UartHandle, UART_IT_RXNE);
}
#endif
#ifdef USRAT3_ENABLE
/* USART3 init function */
static void MX_USART3_UART_Init(bsp_usart_t *usart, uint32_t BaudRate)
{
    if (usart == NULL)
    {
        _Error_Handler(__FILE__, __LINE__);
    }

    huart3.Instance = USART3;
    huart3.Init.BaudRate = BaudRate;
    huart3.Init.WordLength = UART_WORDLENGTH_8B;
    huart3.Init.StopBits = UART_STOPBITS_1;
    huart3.Init.Parity = UART_PARITY_NONE;
    huart3.Init.Mode = UART_MODE_TX_RX;
    huart3.Init.HwFlowCtl = UART_HWCONTROL_NONE;
    huart3.Init.OverSampling = UART_OVERSAMPLING_16;
    if (HAL_UART_Init(&huart3) != HAL_OK)
    {
        _Error_Handler(__FILE__, __LINE__);
    }
    usart->UartHandle = &huart3;
    /* enable rx irq */
    HAL_NVIC_SetPriority(USART3_IRQn, BSP_USART_IRQ_PRE_PRI, BSP_USART_IRQ_SUB_PRI);
    HAL_NVIC_EnableIRQ(USART3_IRQn);
    /* enable interrupt */
    __HAL_UART_ENABLE_IT(usart->UartHandle, UART_IT_RXNE);
}
#endif
#ifdef URAT4_ENABLE
/* UART4 init function */
static void MX_UART4_Init(bsp_usart_t *usart, uint32_t BaudRate)
{
    if (usart == NULL)
    {
        _Error_Handler(__FILE__, __LINE__);
    }

    huart4.Instance = UART4;
    huart4.Init.BaudRate = BaudRate;
    huart4.Init.WordLength = UART_WORDLENGTH_8B;
    huart4.Init.StopBits = UART_STOPBITS_1;
    huart4.Init.Parity = UART_PARITY_NONE;
    huart4.Init.Mode = UART_MODE_TX_RX;
    huart4.Init.HwFlowCtl = UART_HWCONTROL_NONE;
    huart4.Init.OverSampling = UART_OVERSAMPLING_16;
    if (HAL_UART_Init(&huart4) != HAL_OK)
    {
        _Error_Handler(__FILE__, __LINE__);
    }
    usart->UartHandle = &huart4;
    /* enable rx irq */
    HAL_NVIC_SetPriority(UART4_IRQn, BSP_USART_IRQ_PRE_PRI, BSP_USART_IRQ_SUB_PRI);
    HAL_NVIC_EnableIRQ(UART4_IRQn);
    /* enable interrupt */
    __HAL_UART_ENABLE_IT(usart->UartHandle, UART_IT_RXNE);
}
#endif
#ifdef URAT5_ENABLE
/* UART5 init function */
static void MX_UART5_Init(bsp_usart_t *usart, uint32_t BaudRate)
{
    if (usart == NULL)
    {
        _Error_Handler(__FILE__, __LINE__);
    }

    huart5.Instance = UART5;
    huart5.Init.BaudRate = BaudRate;
    huart5.Init.WordLength = UART_WORDLENGTH_8B;
    huart5.Init.StopBits = UART_STOPBITS_1;
    huart5.Init.Parity = UART_PARITY_NONE;
    huart5.Init.Mode = UART_MODE_TX_RX;
    huart5.Init.HwFlowCtl = UART_HWCONTROL_NONE;
    huart5.Init.OverSampling = UART_OVERSAMPLING_16;
    if (HAL_UART_Init(&huart5) != HAL_OK)
    {
        _Error_Handler(__FILE__, __LINE__);
    }
    usart->UartHandle = &huart5;
    /* enable rx irq */
    HAL_NVIC_SetPriority(UART5_IRQn, BSP_USART_IRQ_PRE_PRI, BSP_USART_IRQ_SUB_PRI);
    HAL_NVIC_EnableIRQ(UART5_IRQn);
    /* enable interrupt */
    __HAL_UART_ENABLE_IT(usart->UartHandle, UART_IT_RXNE);
}
#endif
#ifdef USRAT6_ENABLE
/* USART6 init function */
static void MX_USART6_UART_Init(bsp_usart_t *usart, uint32_t BaudRate)
{
    if (usart == NULL)
    {
        _Error_Handler(__FILE__, __LINE__);
    }

    huart6.Instance = USART6;
    huart6.Init.BaudRate = BaudRate;
    huart6.Init.WordLength = UART_WORDLENGTH_8B;
    huart6.Init.StopBits = UART_STOPBITS_1;
    huart6.Init.Parity = UART_PARITY_NONE;
    huart6.Init.Mode = UART_MODE_TX_RX;
    huart6.Init.HwFlowCtl = UART_HWCONTROL_NONE;
    huart6.Init.OverSampling = UART_OVERSAMPLING_16;
    if (HAL_UART_Init(&huart6) != HAL_OK)
    {
        _Error_Handler(__FILE__, __LINE__);
    }
    usart->UartHandle = &huart6;
    /* enable rx irq */
    HAL_NVIC_SetPriority(USART6_IRQn, BSP_USART_IRQ_PRE_PRI, BSP_USART_IRQ_SUB_PRI);
    HAL_NVIC_EnableIRQ(USART6_IRQn);
    /* enable interrupt */
    __HAL_UART_ENABLE_IT(usart->UartHandle, UART_IT_RXNE);
}
#endif

void HAL_UART_MspInit(UART_HandleTypeDef *huart)
{
    GPIO_InitTypeDef GPIO_InitStruct;

    /* DMA controller clock enable */
    __HAL_RCC_DMA1_CLK_ENABLE();
    __HAL_RCC_DMA2_CLK_ENABLE();

#ifndef URAT4_ENABLE
    if (0) {}
#else
    if (huart->Instance == UART4)
    {
        /* Peripheral clock enable */
        __HAL_RCC_UART4_CLK_ENABLE();
        /* GPIO Ports Clock Enable */
        __HAL_RCC_GPIOC_CLK_ENABLE();

        /**UART4 GPIO Configuration
        PC10     ------> UART4_TX
        PC11     ------> UART4_RX
        */
        GPIO_InitStruct.Pin = GPIO_PIN_10 | GPIO_PIN_11;
        GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
        GPIO_InitStruct.Pull = GPIO_PULLUP;
        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
        GPIO_InitStruct.Alternate = GPIO_AF8_UART4;
        HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

        /* UART4 DMA Init */
#ifdef DRV_UART4_USE_DMA_TX
        /* UART4_TX Init */
        hdma_uart4_tx.Instance = DMA1_Stream4;
        hdma_uart4_tx.Init.Channel = DMA_CHANNEL_4;
        hdma_uart4_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
        hdma_uart4_tx.Init.PeriphInc = DMA_PINC_DISABLE;
        hdma_uart4_tx.Init.MemInc = DMA_MINC_ENABLE;
        hdma_uart4_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
        hdma_uart4_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
        hdma_uart4_tx.Init.Mode = DMA_NORMAL;
        hdma_uart4_tx.Init.Priority = DMA_PRIORITY_LOW;
        hdma_uart4_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
        if (HAL_DMA_Init(&hdma_uart4_tx) != HAL_OK)
        {
            _Error_Handler(__FILE__, __LINE__);
        }

        __HAL_LINKDMA(huart, hdmatx, hdma_uart4_tx);
        /* DMA1_Stream4_IRQn interrupt configuration */
        HAL_NVIC_SetPriority(DMA1_Stream4_IRQn, BSP_USART_IRQ_PRE_PRI, BSP_USART_IRQ_SUB_PRI);
        HAL_NVIC_EnableIRQ(DMA1_Stream4_IRQn);
#endif
#ifdef DRV_UART4_USE_DMA_RX
        /* UART4_RX Init */
        hdma_uart4_rx.Instance = DMA1_Stream2;
        hdma_uart4_rx.Init.Channel = DMA_CHANNEL_4;
        hdma_uart4_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
        hdma_uart4_rx.Init.PeriphInc = DMA_PINC_DISABLE;
        hdma_uart4_rx.Init.MemInc = DMA_MINC_ENABLE;
        hdma_uart4_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
        hdma_uart4_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
        hdma_uart4_rx.Init.Mode = DMA_NORMAL;
        hdma_uart4_rx.Init.Priority = DMA_PRIORITY_LOW;
        hdma_uart4_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
        if (HAL_DMA_Init(&hdma_uart4_rx) != HAL_OK)
        {
            _Error_Handler(__FILE__, __LINE__);
        }

        __HAL_LINKDMA(huart, hdmarx, hdma_uart4_rx);
        /* DMA1_Stream2_IRQn interrupt configuration */
        HAL_NVIC_SetPriority(DMA1_Stream2_IRQn, BSP_USART_IRQ_PRE_PRI, BSP_USART_IRQ_SUB_PRI);
        HAL_NVIC_EnableIRQ(DMA1_Stream2_IRQn);
#endif
    }
#endif
#ifdef URAT5_ENABLE
    else if (huart->Instance == UART5)
    {
        /* Peripheral clock enable */
        __HAL_RCC_UART5_CLK_ENABLE();
        /* GPIO Ports Clock Enable */
        __HAL_RCC_GPIOD_CLK_ENABLE();
        __HAL_RCC_GPIOC_CLK_ENABLE();

        /**UART5 GPIO Configuration
        PC12     ------> UART5_TX
        PD2     ------> UART5_RX
        */
        GPIO_InitStruct.Pin = GPIO_PIN_12;
        GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
        GPIO_InitStruct.Pull = GPIO_PULLUP;
        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
        GPIO_InitStruct.Alternate = GPIO_AF8_UART5;
        HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

        GPIO_InitStruct.Pin = GPIO_PIN_2;
        GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
        GPIO_InitStruct.Pull = GPIO_PULLUP;
        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
        GPIO_InitStruct.Alternate = GPIO_AF8_UART5;
        HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);

        /* UART5 DMA Init */
#ifdef DRV_UART5_USE_DMA_TX
        /* UART5_TX Init */
        hdma_uart5_tx.Instance = DMA1_Stream7;
        hdma_uart5_tx.Init.Channel = DMA_CHANNEL_4;
        hdma_uart5_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
        hdma_uart5_tx.Init.PeriphInc = DMA_PINC_DISABLE;
        hdma_uart5_tx.Init.MemInc = DMA_MINC_ENABLE;
        hdma_uart5_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
        hdma_uart5_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
        hdma_uart5_tx.Init.Mode = DMA_NORMAL;
        hdma_uart5_tx.Init.Priority = DMA_PRIORITY_LOW;
        hdma_uart5_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
        if (HAL_DMA_Init(&hdma_uart5_tx) != HAL_OK)
        {
            _Error_Handler(__FILE__, __LINE__);
        }

        __HAL_LINKDMA(huart, hdmatx, hdma_uart5_tx);
        /* DMA1_Stream7_IRQn interrupt configuration */
        HAL_NVIC_SetPriority(DMA1_Stream7_IRQn, BSP_USART_IRQ_PRE_PRI, BSP_USART_IRQ_SUB_PRI);
        HAL_NVIC_EnableIRQ(DMA1_Stream7_IRQn);
#endif
#ifdef DRV_UART5_USE_DMA_RX
        /* UART5_RX Init */
        hdma_uart5_rx.Instance = DMA1_Stream0;
        hdma_uart5_rx.Init.Channel = DMA_CHANNEL_4;
        hdma_uart5_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
        hdma_uart5_rx.Init.PeriphInc = DMA_PINC_DISABLE;
        hdma_uart5_rx.Init.MemInc = DMA_MINC_ENABLE;
        hdma_uart5_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
        hdma_uart5_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
        hdma_uart5_rx.Init.Mode = DMA_NORMAL;
        hdma_uart5_rx.Init.Priority = DMA_PRIORITY_LOW;
        hdma_uart5_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
        if (HAL_DMA_Init(&hdma_uart5_rx) != HAL_OK)
        {
            _Error_Handler(__FILE__, __LINE__);
        }

        __HAL_LINKDMA(huart, hdmarx, hdma_uart5_rx);
        /* DMA1_Stream0_IRQn interrupt configuration */
        HAL_NVIC_SetPriority(DMA1_Stream0_IRQn, BSP_USART_IRQ_PRE_PRI, BSP_USART_IRQ_SUB_PRI);
        HAL_NVIC_EnableIRQ(DMA1_Stream0_IRQn);
#endif
    }
#endif
#ifdef USRAT1_ENABLE
    else if (huart->Instance == USART1)
    {
        /* Peripheral clock enable */
        __HAL_RCC_USART1_CLK_ENABLE();
        /* GPIO Ports Clock Enable */
        __HAL_RCC_GPIOA_CLK_ENABLE();


        /**USART1 GPIO Configuration
        PB6     ------> USART1_TX
        PA7     ------> USART1_RX
        */
        GPIO_InitStruct.Pin = GPIO_PIN_6 | GPIO_PIN_7;
        GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
        GPIO_InitStruct.Pull = GPIO_PULLUP;
        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
        GPIO_InitStruct.Alternate = GPIO_AF7_USART1;
        HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

        /* USART1 DMA Init */
#ifdef DRV_USART1_USE_DMA_TX
        /* USART1_TX Init */
        hdma_usart1_tx.Instance = DMA2_Stream7;
        hdma_usart1_tx.Init.Channel = DMA_CHANNEL_4;
        hdma_usart1_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
        hdma_usart1_tx.Init.PeriphInc = DMA_PINC_DISABLE;
        hdma_usart1_tx.Init.MemInc = DMA_MINC_ENABLE;
        hdma_usart1_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
        hdma_usart1_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
        hdma_usart1_tx.Init.Mode = DMA_NORMAL;
        hdma_usart1_tx.Init.Priority = DMA_PRIORITY_LOW;
        hdma_usart1_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
        if (HAL_DMA_Init(&hdma_usart1_tx) != HAL_OK)
        {
            _Error_Handler(__FILE__, __LINE__);
        }

        __HAL_LINKDMA(huart, hdmatx, hdma_usart1_tx);
        /* DMA2_Stream7_IRQn interrupt configuration */
        HAL_NVIC_SetPriority(DMA2_Stream7_IRQn, BSP_USART_IRQ_PRE_PRI, BSP_USART_IRQ_SUB_PRI);
        HAL_NVIC_EnableIRQ(DMA2_Stream7_IRQn);
#endif
#ifdef DRV_USART1_USE_DMA_RX
        /* USART1_RX Init */
        hdma_usart1_rx.Instance = DMA2_Stream2;
        hdma_usart1_rx.Init.Channel = DMA_CHANNEL_4;
        hdma_usart1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
        hdma_usart1_rx.Init.PeriphInc = DMA_PINC_DISABLE;
        hdma_usart1_rx.Init.MemInc = DMA_MINC_ENABLE;
        hdma_usart1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
        hdma_usart1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
        hdma_usart1_rx.Init.Mode = DMA_NORMAL;
        hdma_usart1_rx.Init.Priority = DMA_PRIORITY_LOW;
        hdma_usart1_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
        if (HAL_DMA_Init(&hdma_usart1_rx) != HAL_OK)
        {
            _Error_Handler(__FILE__, __LINE__);
        }

        __HAL_LINKDMA(huart, hdmarx, hdma_usart1_rx);
        /* DMA2_Stream2_IRQn interrupt configuration */
        HAL_NVIC_SetPriority(DMA2_Stream2_IRQn, BSP_USART_IRQ_PRE_PRI, BSP_USART_IRQ_SUB_PRI);
        HAL_NVIC_EnableIRQ(DMA2_Stream2_IRQn);
#endif
    }
#endif
#ifdef USRAT2_ENABLE
    else if (huart->Instance == USART2)
    {
        /* Peripheral clock enable */
        __HAL_RCC_USART2_CLK_ENABLE();
        /* GPIO Ports Clock Enable */
        __HAL_RCC_GPIOA_CLK_ENABLE();

        /**USART2 GPIO Configuration
        PA2     ------> USART2_TX
        PA3     ------> USART2_RX
        */
        GPIO_InitStruct.Pin = GPIO_PIN_2 | GPIO_PIN_3;
        GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
        GPIO_InitStruct.Pull = GPIO_PULLUP;
        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
        GPIO_InitStruct.Alternate = GPIO_AF7_USART2;
        HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

        /* USART2 DMA Init */
#ifdef DRV_USART2_USE_DMA_TX
        /* USART2_TX Init */
        hdma_usart2_tx.Instance = DMA1_Stream6;
        hdma_usart2_tx.Init.Channel = DMA_CHANNEL_4;
        hdma_usart2_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
        hdma_usart2_tx.Init.PeriphInc = DMA_PINC_DISABLE;
        hdma_usart2_tx.Init.MemInc = DMA_MINC_ENABLE;
        hdma_usart2_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
        hdma_usart2_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
        hdma_usart2_tx.Init.Mode = DMA_NORMAL;
        hdma_usart2_tx.Init.Priority = DMA_PRIORITY_LOW;
        hdma_usart2_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
        if (HAL_DMA_Init(&hdma_usart2_tx) != HAL_OK)
        {
            _Error_Handler(__FILE__, __LINE__);
        }

        __HAL_LINKDMA(huart, hdmatx, hdma_usart2_tx);
        /* DMA1_Stream6_IRQn interrupt configuration */
        HAL_NVIC_SetPriority(DMA1_Stream6_IRQn, BSP_USART_IRQ_PRE_PRI, BSP_USART_IRQ_SUB_PRI);
        HAL_NVIC_EnableIRQ(DMA1_Stream6_IRQn);
#endif
#ifdef DRV_USART2_USE_DMA_RX
        /* USART2_RX Init */
        hdma_usart2_rx.Instance = DMA1_Stream5;
        hdma_usart2_rx.Init.Channel = DMA_CHANNEL_4;
        hdma_usart2_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
        hdma_usart2_rx.Init.PeriphInc = DMA_PINC_DISABLE;
        hdma_usart2_rx.Init.MemInc = DMA_MINC_ENABLE;
        hdma_usart2_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
        hdma_usart2_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
        hdma_usart2_rx.Init.Mode = DMA_NORMAL;
        hdma_usart2_rx.Init.Priority = DMA_PRIORITY_LOW;
        hdma_usart2_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
        if (HAL_DMA_Init(&hdma_usart2_rx) != HAL_OK)
        {
            _Error_Handler(__FILE__, __LINE__);
        }

        __HAL_LINKDMA(huart, hdmarx, hdma_usart2_rx);
        /* DMA1_Stream5_IRQn interrupt configuration */
        HAL_NVIC_SetPriority(DMA1_Stream5_IRQn, BSP_USART_IRQ_PRE_PRI, BSP_USART_IRQ_SUB_PRI);
        HAL_NVIC_EnableIRQ(DMA1_Stream5_IRQn);
#endif
    }
#endif
#ifdef USRAT3_ENABLE
    else if (huart->Instance == USART3)
    {
        /* Peripheral clock enable */
        __HAL_RCC_USART3_CLK_ENABLE();
        /* GPIO Ports Clock Enable */
        __HAL_RCC_GPIOD_CLK_ENABLE();

        /**USART3 GPIO Configuration
        PD8     ------> USART3_TX
        PD9     ------> USART3_RX
        */
        GPIO_InitStruct.Pin = GPIO_PIN_8 | GPIO_PIN_9;
        GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
        GPIO_InitStruct.Pull = GPIO_PULLUP;
        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
        GPIO_InitStruct.Alternate = GPIO_AF7_USART3;
        HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);

        /* USART3 DMA Init */
#ifdef DRV_USART3_USE_DMA_TX
        /* USART3_TX Init */
        hdma_usart3_tx.Instance = DMA1_Stream3;
        hdma_usart3_tx.Init.Channel = DMA_CHANNEL_4;
        hdma_usart3_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
        hdma_usart3_tx.Init.PeriphInc = DMA_PINC_DISABLE;
        hdma_usart3_tx.Init.MemInc = DMA_MINC_ENABLE;
        hdma_usart3_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
        hdma_usart3_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
        hdma_usart3_tx.Init.Mode = DMA_NORMAL;
        hdma_usart3_tx.Init.Priority = DMA_PRIORITY_LOW;
        hdma_usart3_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
        if (HAL_DMA_Init(&hdma_usart3_tx) != HAL_OK)
        {
            _Error_Handler(__FILE__, __LINE__);
        }

        __HAL_LINKDMA(huart, hdmatx, hdma_usart3_tx);
        /* DMA1_Stream3_IRQn interrupt configuration */
        HAL_NVIC_SetPriority(DMA1_Stream3_IRQn, BSP_USART_IRQ_PRE_PRI, BSP_USART_IRQ_SUB_PRI);
        HAL_NVIC_EnableIRQ(DMA1_Stream3_IRQn);
#endif
#ifdef DRV_USART3_USE_DMA_RX
        /* USART3_RX Init */
        hdma_usart3_rx.Instance = DMA1_Stream1;
        hdma_usart3_rx.Init.Channel = DMA_CHANNEL_4;
        hdma_usart3_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
        hdma_usart3_rx.Init.PeriphInc = DMA_PINC_DISABLE;
        hdma_usart3_rx.Init.MemInc = DMA_MINC_ENABLE;
        hdma_usart3_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
        hdma_usart3_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
        hdma_usart3_rx.Init.Mode = DMA_NORMAL;
        hdma_usart3_rx.Init.Priority = DMA_PRIORITY_LOW;
        hdma_usart3_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
        if (HAL_DMA_Init(&hdma_usart3_rx) != HAL_OK)
        {
            _Error_Handler(__FILE__, __LINE__);
        }

        __HAL_LINKDMA(huart, hdmarx, hdma_usart3_rx);
        /* DMA1_Stream1_IRQn interrupt configuration */
        HAL_NVIC_SetPriority(DMA1_Stream1_IRQn, BSP_USART_IRQ_PRE_PRI, BSP_USART_IRQ_SUB_PRI);
        HAL_NVIC_EnableIRQ(DMA1_Stream1_IRQn);
#endif
    }
#endif
#ifdef USRAT6_ENABLE
    else if (huart->Instance == USART6)
    {
        /* Peripheral clock enable */
        __HAL_RCC_USART6_CLK_ENABLE();
        /* GPIO Ports Clock Enable */
        __HAL_RCC_GPIOC_CLK_ENABLE();

        /**USART6 GPIO Configuration
        PC6     ------> USART6_TX
        PC7     ------> USART6_RX
        */
        GPIO_InitStruct.Pin = GPIO_PIN_6 | GPIO_PIN_7;
        GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
        GPIO_InitStruct.Pull = GPIO_PULLUP;
        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
        GPIO_InitStruct.Alternate = GPIO_AF8_USART6;
        HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

        /* USART6 DMA Init */
#ifdef DRV_USART6_USE_DMA_TX
        /* USART6_TX Init */
        hdma_usart6_tx.Instance = DMA2_Stream6;
        hdma_usart6_tx.Init.Channel = DMA_CHANNEL_5;
        hdma_usart6_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
        hdma_usart6_tx.Init.PeriphInc = DMA_PINC_DISABLE;
        hdma_usart6_tx.Init.MemInc = DMA_MINC_ENABLE;
        hdma_usart6_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
        hdma_usart6_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
        hdma_usart6_tx.Init.Mode = DMA_NORMAL;
        hdma_usart6_tx.Init.Priority = DMA_PRIORITY_LOW;
        hdma_usart6_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
        if (HAL_DMA_Init(&hdma_usart6_tx) != HAL_OK)
        {
            _Error_Handler(__FILE__, __LINE__);
        }

        __HAL_LINKDMA(huart, hdmatx, hdma_usart6_tx);
        /* DMA2_Stream6_IRQn interrupt configuration */
        HAL_NVIC_SetPriority(DMA2_Stream6_IRQn, BSP_USART_IRQ_PRE_PRI, BSP_USART_IRQ_SUB_PRI);
        HAL_NVIC_EnableIRQ(DMA2_Stream6_IRQn);
#endif
#ifdef DRV_USART6_USE_DMA_RX
        /* USART6_RX Init */
        hdma_usart6_rx.Instance = DMA2_Stream1;
        hdma_usart6_rx.Init.Channel = DMA_CHANNEL_5;
        hdma_usart6_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
        hdma_usart6_rx.Init.PeriphInc = DMA_PINC_DISABLE;
        hdma_usart6_rx.Init.MemInc = DMA_MINC_ENABLE;
        hdma_usart6_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
        hdma_usart6_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
        hdma_usart6_rx.Init.Mode = DMA_NORMAL;
        hdma_usart6_rx.Init.Priority = DMA_PRIORITY_LOW;
        hdma_usart6_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
        if (HAL_DMA_Init(&hdma_usart6_rx) != HAL_OK)
        {
            _Error_Handler(__FILE__, __LINE__);
        }

        __HAL_LINKDMA(huart, hdmarx, hdma_usart6_rx);
        /* DMA2_Stream1_IRQn interrupt configuration */
        HAL_NVIC_SetPriority(DMA2_Stream1_IRQn, BSP_USART_IRQ_PRE_PRI, BSP_USART_IRQ_SUB_PRI);
        HAL_NVIC_EnableIRQ(DMA2_Stream1_IRQn);
#endif
    }
#endif
}

void HAL_UART_MspDeInit(UART_HandleTypeDef *huart)
{
#ifndef URAT4_ENABLE
    if (0) {}
#else
    if (huart->Instance == UART4)
    {
        /* Peripheral clock disable */
        __HAL_RCC_UART4_CLK_DISABLE();

        /**UART4 GPIO Configuration
        PC10     ------> UART4_TX
        PC11     ------> UART4_RX
        */
        HAL_GPIO_DeInit(GPIOC, GPIO_PIN_10 | GPIO_PIN_11);

        /* disable rx irq */
        NVIC_DisableIRQ(UART4_IRQn);
        /* disable interrupt */
        __HAL_UART_DISABLE_IT(huart, UART_IT_RXNE);

        /* UART4 DMA DeInit */
#ifdef DRV_UART4_USE_DMA_TX
        HAL_DMA_DeInit(huart->hdmatx);
        HAL_NVIC_DisableIRQ(DMA1_Stream4_IRQn);
#endif
#ifdef DRV_UART4_USE_DMA_RX
        HAL_DMA_DeInit(huart->hdmarx);
        HAL_NVIC_DisableIRQ(DMA1_Stream2_IRQn);
#endif
    }
#endif
#ifdef URAT5_ENABLE
    else if (huart->Instance == UART5)
    {
        /* Peripheral clock disable */
        __HAL_RCC_UART5_CLK_DISABLE();

        /**UART5 GPIO Configuration
        PC12     ------> UART5_TX
        PD2     ------> UART5_RX
        */
        HAL_GPIO_DeInit(GPIOC, GPIO_PIN_12);
        HAL_GPIO_DeInit(GPIOD, GPIO_PIN_2);

        /* disable rx irq */
        NVIC_DisableIRQ(UART5_IRQn);
        /* disable interrupt */
        __HAL_UART_DISABLE_IT(huart, UART_IT_RXNE);

        /* UART5 DMA DeInit */
#ifdef DRV_UART5_USE_DMA_TX
        HAL_DMA_DeInit(huart->hdmatx);
        HAL_NVIC_DisableIRQ(DMA1_Stream7_IRQn);
#endif
#ifdef DRV_UART5_USE_DMA_RX
        HAL_DMA_DeInit(huart->hdmarx);
        HAL_NVIC_DisableIRQ(DMA1_Stream0_IRQn);
#endif
    }
#endif
#ifdef USRAT1_ENABLE
    else if (huart->Instance == USART1)
    {
        /* Peripheral clock disable */
        __HAL_RCC_USART1_CLK_DISABLE();

        /**USART1 GPIO Configuration
        PA9     ------> USART1_TX
        PA10     ------> USART1_RX
        */
        HAL_GPIO_DeInit(GPIOA, GPIO_PIN_9 | GPIO_PIN_10);

        /* disable rx irq */
        NVIC_DisableIRQ(USART1_IRQn);
        /* disable interrupt */
        __HAL_UART_DISABLE_IT(huart, UART_IT_RXNE);

        /* USART1 DMA DeInit */
#ifdef DRV_USART1_USE_DMA_TX
        HAL_DMA_DeInit(huart->hdmatx);
        HAL_NVIC_DisableIRQ(DMA2_Stream7_IRQn);
#endif
#ifdef DRV_USART1_USE_DMA_RX
        HAL_DMA_DeInit(huart->hdmarx);
        HAL_NVIC_DisableIRQ(DMA2_Stream2_IRQn);
#endif
    }
#endif
#ifdef USRAT2_ENABLE
    else if (huart->Instance == USART2)
    {
        /* Peripheral clock disable */
        __HAL_RCC_USART2_CLK_DISABLE();

        /**USART2 GPIO Configuration
        PA2     ------> USART2_TX
        PA3     ------> USART2_RX
        */
        HAL_GPIO_DeInit(GPIOA, GPIO_PIN_2 | GPIO_PIN_3);

        /* disable rx irq */
        NVIC_DisableIRQ(USART2_IRQn);
        /* disable interrupt */
        __HAL_UART_DISABLE_IT(huart, UART_IT_RXNE);

        /* USART2 DMA DeInit */
#ifdef DRV_USART2_USE_DMA_TX
        HAL_DMA_DeInit(huart->hdmatx);
        HAL_NVIC_DisableIRQ(DMA1_Stream6_IRQn);
#endif
#ifdef DRV_USART2_USE_DMA_RX
        HAL_DMA_DeInit(huart->hdmarx);
        HAL_NVIC_DisableIRQ(DMA1_Stream5_IRQn);
#endif
    }
#endif
#ifdef USRAT3_ENABLE
    else if (huart->Instance == USART3)
    {
        /* Peripheral clock disable */
        __HAL_RCC_USART3_CLK_DISABLE();

        /**USART3 GPIO Configuration
        PD8     ------> USART3_TX
        PD9     ------> USART3_RX
        */
        HAL_GPIO_DeInit(GPIOD, GPIO_PIN_8 | GPIO_PIN_9);

        /* disable rx irq */
        NVIC_DisableIRQ(USART3_IRQn);
        /* disable interrupt */
        __HAL_UART_DISABLE_IT(huart, UART_IT_RXNE);

        /* USART3 DMA DeInit */
#ifdef DRV_USART3_USE_DMA_TX
        HAL_DMA_DeInit(huart->hdmatx);
        HAL_NVIC_DisableIRQ(DMA1_Stream3_IRQn);
#endif
#ifdef DRV_USART3_USE_DMA_RX
        HAL_DMA_DeInit(huart->hdmarx);
        HAL_NVIC_DisableIRQ(DMA1_Stream1_IRQn);
#endif
    }
#endif
#ifdef USRAT6_ENABLE
    else if (huart->Instance == USART6)
    {
        /* Peripheral clock disable */
        __HAL_RCC_USART6_CLK_DISABLE();

        /**USART6 GPIO Configuration
        PC6     ------> USART6_TX
        PC7     ------> USART6_RX
        */
        HAL_GPIO_DeInit(GPIOC, GPIO_PIN_6 | GPIO_PIN_7);

        /* disable rx irq */
        NVIC_DisableIRQ(USART6_IRQn);
        /* disable interrupt */
        __HAL_UART_DISABLE_IT(huart, UART_IT_RXNE);

        /* USART6 DMA DeInit */
#ifdef DRV_USART6_USE_DMA_TX
        HAL_DMA_DeInit(huart->hdmatx);
        HAL_NVIC_DisableIRQ(DMA2_Stream6_IRQn);
#endif
#ifdef DRV_USART6_USE_DMA_RX
        HAL_DMA_DeInit(huart->hdmarx);
        HAL_NVIC_DisableIRQ(DMA2_Stream1_IRQn);
#endif
    }
#endif
}

/**
* @brief This function handles DMA1 stream0 global interrupt.
*/
#if defined URAT5_ENABLE && defined DRV_UART5_USE_DMA_RX
void DMA1_Stream0_IRQHandler(void)
{
    bsp_usart_dma_irq(&hdma_uart5_rx);
}
#endif
/**
* @brief This function handles DMA1 stream1 global interrupt.
*/
#if defined USRAT3_ENABLE && defined DRV_USART3_USE_DMA_RX
void DMA1_Stream1_IRQHandler(void)
{
    bsp_usart_dma_irq(&hdma_usart3_rx);
}
#endif
/**
* @brief This function handles DMA1 stream2 global interrupt.
*/
#if defined URAT4_ENABLE && defined DRV_UART4_USE_DMA_RX
void DMA1_Stream2_IRQHandler(void)
{
    bsp_usart_dma_irq(&hdma_uart4_rx);
}
#endif
/**
* @brief This function handles DMA1 stream3 global interrupt.
*/
#if defined USRAT3_ENABLE && defined DRV_USART3_USE_DMA_TX
void DMA1_Stream3_IRQHandler(void)
{
    bsp_usart_dma_irq(&hdma_usart3_tx);
}
#endif
/**
* @brief This function handles DMA1 stream4 global interrupt.
*/
#if defined URAT4_ENABLE && defined DRV_UART4_USE_DMA_TX
void DMA1_Stream4_IRQHandler(void)
{
    bsp_usart_dma_irq(&hdma_uart4_tx);
}
#endif
/**
* @brief This function handles DMA1 stream5 global interrupt.
*/
#if defined USRAT2_ENABLE && defined DRV_USART2_USE_DMA_RX
void DMA1_Stream5_IRQHandler(void)
{
    bsp_usart_dma_irq(&hdma_usart2_rx);
}
#endif
/**
* @brief This function handles DMA1 stream6 global interrupt.
*/
#if defined USRAT2_ENABLE && defined DRV_USART2_USE_DMA_TX
void DMA1_Stream6_IRQHandler(void)
{
    bsp_usart_dma_irq(&hdma_usart2_tx);
}
#endif
/**
* @brief This function handles DMA1 stream7 global interrupt.
*/
#if defined URAT5_ENABLE && defined DRV_UART5_USE_DMA_TX
void DMA1_Stream7_IRQHandler(void)
{
    bsp_usart_dma_irq(&hdma_uart5_tx);
}
#endif
/**
* @brief This function handles DMA2 stream1 global interrupt.
*/
#if defined USRAT6_ENABLE && defined DRV_USART6_USE_DMA_RX
void DMA2_Stream1_IRQHandler(void)
{
    bsp_usart_dma_irq(&hdma_usart6_rx);
}
#endif
/**
* @brief This function handles DMA2 stream2 global interrupt.
*/
#if defined USRAT1_ENABLE && defined DRV_USART1_USE_DMA_RX
void DMA2_Stream2_IRQHandler(void)
{
    bsp_usart_dma_irq(&hdma_usart1_rx);
}
#endif
/**
* @brief This function handles DMA2 stream6 global interrupt.
*/
#if defined USRAT6_ENABLE && defined DRV_USART6_USE_DMA_TX
void DMA2_Stream6_IRQHandler(void)
{
    bsp_usart_dma_irq(&hdma_usart6_tx);
}
#endif
/**
* @brief This function handles DMA2 stream7 global interrupt.
*/
#if defined USRAT1_ENABLE && defined DRV_USART1_USE_DMA_TX
void DMA2_Stream7_IRQHandler(void)
{
    bsp_usart_dma_irq(&hdma_usart1_tx);
}
#endif

/**
* @brief This function handles USART1 global interrupt.
*/
#ifdef USRAT1_ENABLE
void USART1_IRQHandler(void)
{
    bsp_usart_irq(BSP_USART1);
}
#endif
/**
* @brief This function handles USART2 global interrupt.
*/
#ifdef USRAT2_ENABLE
void USART2_IRQHandler(void)
{
    bsp_usart_irq(BSP_USART2);
}
#endif
/**
* @brief This function handles USART3 global interrupt.
*/
#ifdef USRAT3_ENABLE
void USART3_IRQHandler(void)
{
    bsp_usart_irq(BSP_USART3);
}
#endif
/**
* @brief This function handles UART4 global interrupt.
*/
#ifdef URAT4_ENABLE
void UART4_IRQHandler(void)
{
    bsp_usart_irq(BSP_UART4);
}
#endif
/**
* @brief This function handles UART5 global interrupt.
*/
#ifdef URAT5_ENABLE
void UART5_IRQHandler(void)
{
    bsp_usart_irq(BSP_UART5);
}
#endif

/**
* @brief This function handles USART6 global interrupt.
*/
#ifdef USRAT6_ENABLE
void USART6_IRQHandler(void)
{
    bsp_usart_irq(BSP_USART6);
}
#endif

/* Tx Transfer completed callbacks. */
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
    if (huart->Instance == USART1)
    {
        bsp_usart_tx_complete_cb(BSP_USART1);
    }
    else if (huart->Instance == USART2)
    {
        bsp_usart_tx_complete_cb(BSP_USART2);
    }
    else if (huart->Instance == USART3)
    {
        bsp_usart_tx_complete_cb(BSP_USART3);
    }
    else if (huart->Instance == UART4)
    {
        bsp_usart_tx_complete_cb(BSP_UART4);
    }
    else if (huart->Instance == UART5)
    {
        bsp_usart_tx_complete_cb(BSP_UART5);
    }
    else if (huart->Instance == USART6)
    {
        bsp_usart_tx_complete_cb(BSP_USART6);
    }
}

/*---------------------------------------------------------------------------*/
static void bsp_usart_tx_complete_cb(uint32_t uart)
{
    bsp_usart_t *usart;

    if (uart < BSP_USART_MAX)
    {
        usart = &usart_handler[uart];
        if (usart->tx_complete)
        {
            usart->tx_complete(usart->handle);
        }
    }
}

static int32_t _bsp_usart_getc(bsp_usart_t *usart)
{
    int32_t ch = -1;

    if (__HAL_UART_GET_FLAG(usart->UartHandle, UART_FLAG_RXNE) != RESET)
    {
        ch = usart->UartHandle->Instance->DR & 0xff;
    }

    return ch;
}

static void _bsp_usart_rx_isr(bsp_usart_t *usart)
{
    int32_t ch = -1;
    struct usart_rx_fifo *rx_fifo = &usart->rx;

    while (1)
    {
        ch = _bsp_usart_getc(usart);
        if (ch == -1) break;

        rx_fifo->buffer[rx_fifo->in] = ch;
        rx_fifo->in += 1;
        if (rx_fifo->in >= rx_fifo->size) rx_fifo->in = 0;

        /* if the next position is read index, discard this 'read char' */
        if (rx_fifo->in == rx_fifo->out)
        {
            rx_fifo->out += 1;
            rx_fifo->is_full = USART_RX_FULL;
            if (rx_fifo->out >= rx_fifo->size) rx_fifo->out = 0;
        }
    }

    /* invoke callback */
    if (usart->rx_indicate != NULL)
    {
        uint32_t rx_length = (rx_fifo->out >= rx_fifo->in) ? (rx_fifo->out - rx_fifo->in) : (rx_fifo->size - (rx_fifo->in - rx_fifo->out));
        if (rx_length)
        {
            usart->rx_indicate(usart->handle, rx_length);
        }
    }
}

static void bsp_usart_irq(uint32_t uart)
{
    bsp_usart_t *usart;

    BSP_USART_ENTER_ISR();

    if (uart < BSP_USART_MAX)
    {
        usart = &usart_handler[uart];
        if (usart->UartHandle)
        {
            if ((__HAL_UART_GET_FLAG(usart->UartHandle, UART_FLAG_RXNE) != RESET) &&
                    (__HAL_UART_GET_IT_SOURCE(usart->UartHandle, UART_IT_RXNE) != RESET))
            {
                _bsp_usart_rx_isr(usart);
                __HAL_UART_CLEAR_FLAG(usart->UartHandle, UART_FLAG_RXNE); /* Clear RXNE interrupt flag */
            }
            else
            {
                HAL_UART_IRQHandler(usart->UartHandle);
            }
        }
    }

    BSP_USART_EXIT_ISR();
}


static void bsp_usart_dma_irq(DMA_HandleTypeDef *hdma)
{
    BSP_USART_ENTER_ISR();
    HAL_DMA_IRQHandler(hdma);
    BSP_USART_EXIT_ISR();
}

int32_t bsp_usart_dma_tx(uint32_t uart, uint8_t *buf, uint32_t size)
{
    if (uart < BSP_USART_MAX)
    {
        bsp_usart_t *usart = &usart_handler[uart];
        if (usart->UartHandle->hdmatx != NULL &&
                HAL_UART_Transmit_DMA(usart->UartHandle, buf, size) == HAL_OK)
        {
            return size;
        }
    }
    return 0;
}

int32_t bsp_usart_poll_tx(uint32_t uart, uint8_t *buf, uint32_t size, uint32_t timeout)
{
    if (uart < BSP_USART_MAX)
    {
        UART_HandleTypeDef *huart = usart_handler[uart].UartHandle;
        if (huart != NULL)
        {
            HAL_UART_Transmit(huart, buf, size, timeout);
            return (huart->TxXferSize - huart->TxXferCount);
        }
    }
    return 0;
}

int32_t bsp_usart_putc(uint32_t uart, uint8_t c)
{
    return bsp_usart_poll_tx(uart, &c, 1, 1);
}

int32_t bsp_usart_rx_buf_len(uint32_t uart)
{
    struct usart_rx_fifo *rx_fifo = &usart_handler[uart].rx;

    if (uart >= BSP_USART_MAX)
    {
        return -1;
    }

    if (rx_fifo->is_full == USART_RX_FULL)
    {
        return rx_fifo->size; // full
    }
    else if (rx_fifo->out == rx_fifo->in)
    {
        return 0; // empty
    }
    else if (rx_fifo->out > rx_fifo->in)
    {
        return (rx_fifo->out - rx_fifo->in);
    }
    else
    {
        return (rx_fifo->size - (rx_fifo->in - rx_fifo->out));
    }
}

int32_t bsp_usart_rx(uint32_t uart, uint8_t *buf, uint32_t length)
{
    if (uart < BSP_USART_MAX)
    {
        int size;
        struct usart_rx_fifo *rx_fifo;

        size = length;

        rx_fifo = &usart_handler[uart].rx;

        /* read from software FIFO */
        while (length)
        {
            int ch;

            /* there's no data: */
            if ((rx_fifo->out == rx_fifo->in) && (rx_fifo->is_full == !USART_RX_FULL))
            {
                break;
            }

            /* disable interrupt */
            portENTER_CRITICAL();

            /* otherwise there's the data: */
            ch = rx_fifo->buffer[rx_fifo->out];
            rx_fifo->out += 1;
            if (rx_fifo->out >= rx_fifo->size) rx_fifo->out = 0;

            if (rx_fifo->is_full == USART_RX_FULL)
            {
                rx_fifo->is_full = !USART_RX_FULL;
            }

            /* enable interrupt */
            portEXIT_CRITICAL();

            *buf = ch & 0xff;
            buf ++;
            length --;
        }

        return size - length;
    }
    return 0;
}

/**
* @brief bsp_usart_init
*/
int bsp_usart_init(void *handle, uint32_t uart, uint32_t baudrate,
                   usart_isr_rx_indicate_t rx_indicate, usart_isr_tx_complete_t tx_complete)
{
    bsp_usart_t *usart;

    if (uart >= BSP_USART_MAX)
    {
        DBG_LOGE(TAG, "Invalid parameter uart: %d", uart);
        return -1;
    }

    usart = &usart_handler[uart];

    if (usart->handle != NULL)
    {
        DBG_LOGW(TAG, "usart %d already init!", uart);
        if (usart->handle != handle)
        {
            DBG_LOGE(TAG, "usart %d conflict!", uart);
            return -2;
        }
    }

    usart->rx.in = 0;
    usart->rx.out = 0;
    usart->rx.size = USART_RX_FIFO_SIZE;
    usart->rx.is_full = !USART_RX_FULL;
    usart->rx_indicate = rx_indicate;
    usart->tx_complete = tx_complete;
    usart->handle = handle;

    if (uart == BSP_USART_NULL)
    {
        DBG_LOGW(TAG, "usart %d is NULL!", uart);
    }
#ifdef USRAT1_ENABLE
    if (uart == BSP_USART1)
    {
        MX_USART1_UART_Init(usart, baudrate);   // 115200, RS232-1 cli and debug log
    }
#endif
#ifdef USRAT2_ENABLE
    if (uart == BSP_USART2)
    {
        MX_USART2_UART_Init(usart, baudrate);   // 115200, RS232-2
    }
#endif
#ifdef USRAT3_ENABLE
    if (uart == BSP_USART3)
    {
        MX_USART3_UART_Init(usart, baudrate);    // 9600, RS485
    }
#endif
#ifdef URAT4_ENABLE
    if (uart == BSP_UART4)
    {
        MX_UART4_Init(usart, baudrate);         // 9600, gps
    }
#endif
#ifdef URAT5_ENABLE
    if (uart == BSP_UART5)
    {
        MX_UART5_Init(usart, baudrate);         // 115200, gprs, M35
    }
#endif
#ifdef USRAT6_ENABLE
    if (uart == BSP_USART6)
    {
        MX_USART6_UART_Init(usart, baudrate);    // 9600, ble, CC2541
    }
#endif

    return 0;
}

int bsp_usart_deinit(uint32_t uart)
{
#ifdef USRAT1_ENABLE
    if (uart == BSP_USART1)
    {
        bsp_usart_t *usart = &usart_handler[BSP_USART1];
        HAL_UART_MspDeInit(usart->UartHandle);
    }
#endif
#ifdef USRAT2_ENABLE
    if (uart == BSP_USART2)
    {
        bsp_usart_t *usart = &usart_handler[BSP_USART2];
        HAL_UART_MspDeInit(usart->UartHandle);
    }
#endif
#ifdef USRAT3_ENABLE
    if (uart == BSP_USART3)
    {
        bsp_usart_t *usart = &usart_handler[BSP_USART3];
        HAL_UART_MspDeInit(usart->UartHandle);
    }
#endif
#ifdef URAT4_ENABLE
    if (uart == BSP_UART4)
    {
        bsp_usart_t *usart = &usart_handler[BSP_UART4];
        HAL_UART_MspDeInit(usart->UartHandle);
    }
#endif
#ifdef URAT5_ENABLE
    if (uart == BSP_UART5)
    {
        bsp_usart_t *usart = &usart_handler[BSP_UART5];
        HAL_UART_MspDeInit(usart->UartHandle);
    }
#endif
#ifdef USRAT6_ENABLE
    if (uart == BSP_USART6)
    {
        bsp_usart_t *usart = &usart_handler[BSP_USART6];
        HAL_UART_MspDeInit(usart->UartHandle);
    }
#endif
    return 0;
}

/**
  * @}
  */

/******************* (C)COPYRIGHT 2018 ***** END OF FILE *********************/
